use std::ops::DerefMut;
use client::Client;
use listener::{RobotCmdTx, RobotStatusListener};
use tokio::sync::Mutex;

use crate::error::AppErr;

mod client;
mod proto;
pub mod cmd;
pub mod listener;
pub mod adj;

pub use proto::RobotStatus;

struct RobotManager {
    client: Client,
    address: String,
    robot_cmd_tx: RobotCmdTx,
}

static ROBOT_MANAGER: Mutex<Option<RobotManager>> = Mutex::const_new(None);

pub async fn connect(ip: &str) -> Result<(), AppErr> {
    let mut robot = ROBOT_MANAGER.lock().await;

    let client_addr = format!("{}:8080", ip);
    let listen_addr = format!("{}:8083", ip);

    let client = Client::connect(&client_addr).await?;
    let cmd_tx = RobotStatusListener::connect(listen_addr).await?;

    *robot = Some(RobotManager { client, address: client_addr, robot_cmd_tx: cmd_tx });

    Ok(())
}

pub async fn is_connect() -> bool {
    ROBOT_MANAGER.lock().await.is_some()
}

pub async fn request(cmd_id: u32, data: &str) -> Result<(), AppErr> {
    let mut robot = ROBOT_MANAGER.lock().await;
    let mut count = 0;

    loop {
        match robot.deref_mut() {
            Some(robot) => match robot.client.request(cmd_id, data).await {
                
                Ok(()) => {
                    return Ok(());
                }
                
                Err(AppErr::RobotNet(e)) => {
                    log::error!("robot err:{}", e);
                    if count >= 3 {
                        return Err(AppErr::Static("机械臂执行失败 重新连接3次"));
                    }

                    log::info!("机械臂重新连接");
                    let client = Client::connect(&robot.address).await?;
                    robot.client = client;
                    count += 1;
                }

                Err(e) => {
                    return Err(e);
                }
            },

            None => {
                return Err(AppErr::Static("机械臂没有连接"));
            }
        };
    }
}
